﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using IQToolkit;

using AgileFx.ORM.QueryAnalysis;
using AgileFx.ORM;
using AgileFx.ORM.Backends.LinqToSql;

namespace AgileFx.MVC.PerformanceTools.LinqToSql
{
    public class TracingQueryProvider : L2SQueryProvider
    {
        class QueryFinder : IQToolkit.ExpressionVisitor
        {
            public IEntityQuery EntityQuery { get; private set; }

            public new Expression Visit(Expression exp)
            {
                return base.Visit(exp);
            }

            protected override Expression VisitMethodCall(MethodCallExpression m)
            {
                if (m.Arguments.Count > 0)
                    return Visit(m.Arguments.First());
                else
                    return base.Visit(m);
            }

            protected override Expression VisitConstant(ConstantExpression c)
            {
                if (c.Value is IEntityQuery)
                    EntityQuery = c.Value as IEntityQuery;
                return base.VisitConstant(c);
            }
        }

        public TracingQueryProvider(TracingDataContext context)
            : base(context)
        { }

        protected override AgileFx.ORM.IEntityQuery<T> CreateQueryImpl<T>()
        {
            PerformanceSpy.TraceContext.WriteToLog("CreateQuery", typeof(T).ToString());
            return base.CreateQueryImpl<T>();
        }

        public override T ExecuteImpl<T>(System.Linq.Expressions.Expression expression)
        {
            var result = base.ExecuteImpl<T>(expression);

            //Find the entity query from inside the expression
            var finder = new QueryFinder();
            finder.Visit(expression);
            var query = finder.EntityQuery;

            var entityContext = ((query as IQueryable).Provider as EntityQueryProvider).EntityContext;
            var dataContext = (entityContext._InternalServices.TableEntityContext as DataContextWrapper).LinqToSqlContext;

            var analyzer = new QueryTranslationVisitor(new QueryAnalysisContext(entityContext._InternalServices.TypeTranslationUtil));
            var translationResults = analyzer.GetTranslatedResults((query as IQueryable).Expression);

            var l2sQueryable = query.TableEntityQuery.Provider.CreateQuery(translationResults.TranslatedExpression);
            var commandText = dataContext.GetCommand(l2sQueryable).CommandText;            
            
            PerformanceSpy.TraceContext.WriteToLog("Execute", commandText);
            
            return result;
        }
    }
}
